#include <linux/input.h>
#include "hi_mw_media_intf.h"
#include "higo_main.h"
#include "tpHal.h"
extern HigoAic g_higoaic;
static inline HI_S32 HAL_TOUCHPAD_InputBitCheck(HI_S32 bit, const volatile HI_U32 *addr, HI_U32 addrSize)
{
    HI_U32 index = bit / TOUCHAPD_BITLONG;
    if (addrSize <= index) {
        MLOGE("index[%u] should less than  than addrSize[%u],error\n", index, addrSize);
        return 0;
    }
    return 1UL & (addr[index] >> ((HI_U32)bit & (TOUCHAPD_BITLONG - 1)));
}

static HI_S32 HAL_TOUCHPAD_PushSamp(struct input_event *inputEvent, TOUCHPAD_MtInputInfo *inputInfo,
    TOUCHPAD_MtSampleInfo *sampInfo)
{
    HI_S32 touchNum = 0;
    HI_S32 touchSlot;
    for (touchSlot = 0; touchSlot < TOUCHAPD_MAXPOINTNUM; ++touchSlot) {
        if (!inputInfo->touchFilled[touchSlot]) {
            continue; /* touchSlot index has no upadte data */
        }
        sampInfo->info[touchNum].x = inputInfo->x[touchSlot];
        sampInfo->info[touchNum].y = inputInfo->y[touchSlot];
        sampInfo->info[touchNum].pressure = inputInfo->touchPressure[touchSlot];
        /* 1000 mean 1s=1000ms 1ms = 1000us */
        sampInfo->info[touchNum].timeStamp = (inputEvent->time.tv_sec) * 1000u + (inputEvent->time.tv_usec) / 1000u;
        sampInfo->info[touchNum].id = touchSlot;

        inputInfo->touchFilled[touchSlot] = 0;
        touchNum++;
    }
    return touchNum;
}

static HI_S32 HAL_TOUCHPAD_ABSEventFillInputInfo(struct input_event *inputEvent, TOUCHPAD_MtInputInfo *inputInfo)
{
    switch (inputEvent->code) {
        case ABS_PRESSURE:
            inputInfo->touchPressure[inputInfo->touchSlot] = inputEvent->value;
            break;
        case ABS_MT_SLOT:
            if (inputEvent->value < 0) {
                break;
            }
            inputInfo->touchSlot = inputEvent->value;
            if (inputInfo->touchSlot >= TOUCHAPD_MAXPOINTNUM) {
                inputInfo->touchSlot = 0;
            }
            break;
        case ABS_MT_TOUCH_MAJOR:
            inputInfo->touchPressure[inputInfo->touchSlot] = inputEvent->value;
            inputInfo->touchFilled[inputInfo->touchSlot] = 1;
            break;
        case ABS_MT_POSITION_X:
            inputInfo->x[inputInfo->touchSlot] = inputEvent->value;
            inputInfo->touchPressure[inputInfo->touchSlot] = 1;
            inputInfo->touchFilled[inputInfo->touchSlot] = 1;
            break;
        case ABS_MT_POSITION_Y:
            inputInfo->y[inputInfo->touchSlot] = inputEvent->value;
            inputInfo->touchPressure[inputInfo->touchSlot] = 1;
            inputInfo->touchFilled[inputInfo->touchSlot] = 1;
            break;
        case ABS_MT_TRACKING_ID:
            if (inputEvent->value == -1) {
                inputInfo->touchFilled[inputInfo->touchSlot] = 1;
            }
            break;
        default:
            break;
    }
    return HI_SUCCESS;
}

HI_S32 touchDeviceClose(HI_VOID)
{
	HigoAic *self = &g_higoaic;
	close(self->g_touchfd);
    return HI_SUCCESS;
}

HI_S32 touchDeviceReadData(MW_TOUCH_INPUTINFO_S* pstInputData)
{
		static TOUCHPAD_MtInputInfo inputInfo = {0};
		struct input_event inputEvent = {0};
		HI_BOOL dataReadCompleted = HI_FALSE;
		TOUCHPAD_MtSampleInfo sampInfo = {0};
		HigoAic *self = &g_higoaic;
	
		while (dataReadCompleted == HI_FALSE) {
			int ret = FdReadMsg(self->g_touchfd, &inputEvent, sizeof(inputEvent));
			if (ret < 0) {
				LOGE("FdReadMsg detect fd closed\n");
				break;
			} else if (ret == 0) { // no more msg
				break;
			}
	
			switch (inputEvent.type) {
				/* key 0x1 */
				case EV_KEY:
					switch (inputEvent.code) {
						/* 14a 0 */
						case BTN_TOUCH:
							inputInfo.touchPressure[inputInfo.touchSlot] = inputEvent.value;
							inputInfo.touchFilled[inputInfo.touchSlot] = 1;
							break;
						default:
							break;
					}
					break;
	
				/* 0x00 */
				case EV_SYN:
					switch (inputEvent.code) {
						case SYN_REPORT:
						case SYN_MT_REPORT:
						default:
							HAL_TOUCHPAD_PushSamp(&inputEvent, &inputInfo, &sampInfo);
							dataReadCompleted = HI_TRUE;
							break;
					}
					break;
	
				/* 0x3 */
				case EV_ABS:
					HAL_TOUCHPAD_ABSEventFillInputInfo(&inputEvent, &inputInfo);
					break;
				default:
					break;
			}
		}
	
		if (dataReadCompleted) {
			pstInputData->id = sampInfo.info[0].id;
			pstInputData->pressure = sampInfo.info[0].pressure;
			if(self->g_Rotate == HI_TOUCHPAD_ROTATE_90){
				pstInputData->y = sampInfo.info[0].x;
#ifdef HIGO_TOUCH_FLIP_Y
				pstInputData->x = SCREEN_HEIGHT - sampInfo.info[0].y;
#else
				pstInputData->x = sampInfo.info[0].y;
#endif
			}else{
				pstInputData->x = sampInfo.info[0].x;
				pstInputData->y = sampInfo.info[0].y;
			}
			pstInputData->timeStamp = sampInfo.info[0].timeStamp;
			LOGI("got tp coord, x=%d, y=%d\n", pstInputData->x, pstInputData->y);
		}
    return HI_SUCCESS;
}

HI_S32 touchDeviceOpen(HI_S32* ps32Fd)
{	
	HigoAic *self = &g_higoaic;
	HI_U32 inputBits[(ABS_MAX + TOUCHAPD_BITLONG - 1) / TOUCHAPD_BITLONG];
	self->g_touchfd = open(TOUCHAPD_INPUT_DEV, O_RDONLY);
    if (self->g_touchfd < 0) {
        LOGE("open '%s' FAIL, err='%s, %d'\n", TOUCHAPD_INPUT_DEV, strerror(errno), errno);
    } else if (ioctl(self->g_touchfd, EVIOCGBIT(EV_ABS, sizeof(inputBits)), inputBits) < 0) {
        LOGE("ioctl err, err='%s, %d'\n", strerror(errno), errno);
        close(self->g_touchfd);
    } else if ((HAL_TOUCHPAD_InputBitCheck(ABS_MT_POSITION_X, inputBits, sizeof(inputBits)) == 0) ||
        (HAL_TOUCHPAD_InputBitCheck(ABS_MT_POSITION_Y, inputBits, sizeof(inputBits)) == 0) ||
        (HAL_TOUCHPAD_InputBitCheck(ABS_MT_TOUCH_MAJOR, inputBits, sizeof(inputBits)) == 0)) {
        LOGE("could not support the TP device\n");
        LOGE("EV_SYN=%d\n", HAL_TOUCHPAD_InputBitCheck(EV_SYN, inputBits, sizeof(inputBits)));
        LOGE("EV_ABS=%d\n", HAL_TOUCHPAD_InputBitCheck(EV_ABS, inputBits, sizeof(inputBits)));
        LOGE("ABS_MT_POSITION_X=%d\n", HAL_TOUCHPAD_InputBitCheck(ABS_MT_POSITION_X, inputBits, sizeof(inputBits)));
        LOGE("ABS_MT_POSITION_Y=%d\n", HAL_TOUCHPAD_InputBitCheck(ABS_MT_POSITION_Y, inputBits, sizeof(inputBits)));
        LOGE("ABS_MT_TOUCH_MAJOR=%d\n", HAL_TOUCHPAD_InputBitCheck(ABS_MT_TOUCH_MAJOR, inputBits, sizeof(inputBits)));
        close(self->g_touchfd);
    } else {
        FdSetAsync(self->g_touchfd);
		*ps32Fd = self->g_touchfd;
		 return HI_SUCCESS;
    }
	return HI_FAILURE;
}

static HI_S32 HI_GV_TP_ReadData(HIGV_TOUCH_INPUTINFO_S* pstInputData)
{
    MW_TOUCH_INPUTINFO_S stInputInfo;
    HI_S32 ret = memset_s(&stInputInfo, sizeof(stInputInfo), 0x0, sizeof(stInputInfo));
    if (ret != EOK)
    {
        return ret;
    }
    ret = touchDeviceReadData(&stInputInfo);
    if (ret != HI_SUCCESS)
    {
        printf("[Func: %s, Line: %d] HI_MW_TP_ReadData Error.\n\n", __FUNCTION__, __LINE__);
        return ret;
    }
    pstInputData->id = stInputInfo.id;
    pstInputData->x  = stInputInfo.x;
    pstInputData->y = stInputInfo.y;
    pstInputData->pressure = stInputInfo.pressure;
    pstInputData->timeStamp = stInputInfo.timeStamp;
	
	LOGI("HI_GV_TP_ReadData! x:%d y:%d pressure:%d \n",pstInputData->x,pstInputData->y,pstInputData->pressure);
    return ret;
}

static HI_S32 HI_GV_Touch_Hook(HIGV_TOUCH_POINT_S* pTouchEvent)
{
	printf("HI_GV_Touch_Hook!\n");
    return HI_SUCCESS;
}

HI_S32 HI_GV_TOUCH_Register()
{
    HIGV_TOUCH_DEVICE_INPUT_S stInputDevice = {};
    stInputDevice.OpenDevice = touchDeviceOpen;
    stInputDevice.CloseDevie = touchDeviceClose;
    stInputDevice.ReadData   = HI_GV_TP_ReadData;

    (HI_VOID)HI_GV_Gesture_RegisterDevice(&stInputDevice);
    (HI_VOID)HI_GV_Gesture_SetTouchHook(HI_GV_Touch_Hook);
    return HI_SUCCESS;
}

